浅谈hook攻防 您所在的位置:网站首页 api hook技术原理 浅谈hook攻防

浅谈hook攻防

2024-06-08 02:24| 来源: 网络整理| 查看: 265

攻与防都是相对的,只有掌握细节才能更好的对抗。

基础知识

对于Windows系统,它是建立在事件驱动机制上的,说白了就是整个系统都是通过消息传递实现的。hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。所以说,我们可以在系统中自定义钩子,用来监视系统中特定事件的发生,完成特定功能,如屏幕取词,监视日志,截获键盘、鼠标输入等等。

钩子的种类很多,每种钩子可以截获相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子可以分为线程钩子和系统钩子,线程钩子可以监视指定线程的事件消息,系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。

所以说,hook(钩子)就是一个Windows消息的拦截机制,可以拦截单个进程的消息(线程钩子),也可以拦截所有进程的消息(系统钩子),也可以对拦截的消息进行自定义的处理。Windows消息带了一些程序有用的信息,比如Mouse类信息,就带有鼠标所在窗体句柄、鼠标位置等信息,拦截了这些消息,就可以做出例如金山词霸一类的屏幕取词功能。

hook原理

在正确使用钩子函数前,我们先讲解钩子函数的工作原理。当创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果您安装的是一个线程钩子,您进程中的钩子函数将被调用。如果是一个系统钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点要求钩子函数必须在一个动态链接库中,所以如果您想要使用系统钩子,就必须把该钩子函数放到动态链接库中去。

当然有两个例外:工作日志钩子和工作日志回放钩子。这两个钩子的钩子函数必须在安装钩子的线程中。原因是:这两个钩子是用来监控比较底层的硬件事件的,既然是记录和回放,所有的事件就当然都是有先后次序的。所以如果把回调函数放在DLL中,输入的事件被放在几个线程中记录,所以我们无法保证得到正确的次序。故解决的办法是:把钩子函数放到单个的线程中,譬如安装钩子的线程。

几点需要说明的地方:

(1) 如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。   (2) 对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。   (3) 钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。

hook分类

hook从总体来说可以分成两类:

修改函数代码:Inline hook 修改函数地址:IAT hook、SSDT hook、IRP hook、IDT hook等 局限性

如果修改函数地址,其实是很容易被检测到的,例如IAT hook可以通过自己的代码去找到在真正内存中的IAT表,再去对比函数的真正地址,SSDT hook可以通过内核重载比对函数地址来检测到,另外一个局限性就是只能hook对应表里面的函数,IAT表只能hook IAT表导出的函数

所以在实际的应用中一般Inline hook会使用得比较多,虽然相比于修改函数地址更不易检测到,但是还是有技术手段能够进行修改函数代码的检测,本文就基于Inline hook来从防守方制定hook检测的策略和攻击方如何绕过hook检测两方面来浅谈hook技术的攻防

Inline hook

API函数都保存在操作系统提供的DLL文件中,当在程序中使用某个API函数时,在运行程序后,程序会隐式地将API所在的DLL加载入进程中。这样,程序就会像调用自己的函数一样调用API。

在进程中当EXE模块调用CreateFile()函数的时候,会去调用kernel32.dll模块中的CreateFile()函数,因为真正的CreateFile()函数的实现在kernel32.dll模块中。

CreateFile()是API函数,API函数也是由人编写的代码再编译而成的,也有其对应的二进制代码。既然是代码,那么就可以被修改。通过一种“野蛮”的方法来直接修改API函数在内存中的映像,从而对API函数进行HOOK。使用的方法是,直接使用汇编指令的jmp指令将其代码执行流程改变,进而执行我们的代码,这样就使原来的函数的流程改变了。执行完我们的流程以后,可以选择性地执行原来的函数,也可以不继续执行原来的函数。

假设要对某进程的kernel32.dll的CreateFile()函数进行HOOK,首先需要在指定进程中的内存中找到CreateFile()函数的地址,然后修改CreateFile()函数的首地址的代码为jmp MyProc的指令。这样,当指定的进程调用CreateFile()函数时,就会首先跳转到我们的函数当中去执行流程,这样就完成了我们的HOOK了。

hook攻防

这里我选择使用MessageBoxA函数来进行hook的检测,因为MessageBoxA在hook之后能够比较清晰的看到结果

这里我首先使用win32资源文件来创建一个图形窗口,功能是点击开始就会弹窗(不要问我为啥不用MFC写窗口,问就是不会 /狗头),代码如下

// MessageBoxA.cpp : Defines the entry point for the application. // #include "stdafx.h" #include #include "resource.h" BOOL CALLBACK DialogProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { switch(uMsg) { case WM_INITDIALOG : return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_BUTTON_BEGIN : MessageBox(NULL,TEXT("使用hook来更改此界面"),TEXT("文本框"),MB_OK); return TRUE; } break ; case WM_CLOSE: { EndDialog(hwndDlg,0); break; } } return FALSE ; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. DialogBox(hInstance, MAKEINTRESOURCE (IDD_DIALOG_MAIN), NULL, DialogProc); return 0; }

这里生成的是一个没有任何检测代码的MessageBox测试程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KC7SEVdJ-1652105984669)(image-20220403194929538.png)]

点击开始就会弹出文本框,我们hook要达到的目的就是修改文本框里面显示的文字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Keyiz4IT-1652105984670)(image-20220403194940007.png)]

第一层 攻

这里就不细说Inline hook的细节了,跟到关键代码

定义我们要修改文本框内的值存放到szNewText里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yl22N9Tj-1652105984671)(image-20220403222525406.png)]

看一下MessageBox的函数结构

int MessageBox( [in, optional] HWND hWnd, [in, optional] LPCTSTR lpText, [in, optional] LPCTSTR lpCaption, [in] UINT uType );

这里我们直接选择在函数的起始位置进行hook

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7esoJxGv-1652105984672)(image-20220403224835457.png)]

将szNewText赋给eax,再



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有